/*
 *    Copyright 2009 Daniel Hayes
 *    This file is part of PreCT.
 *
 *    PreCT is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    PreCT is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with PreCT.  If not, see <http://www.gnu.org/licenses/>
 */

function PreCTAssistant() {
	this.utils = new Utils();
	this.dbHelper = new DBHelper(this);
	this.scramblers = new Scramblers();
	
	this.times = [];
	this.sessionStartIndex = 0;
	this.sessionId = null;
	
	this.puzzle = "3x3x3";
	this.isOH = false;
	this.isBLD = false;
	this.currentScramble = "";
	this.currentTime = -1;
	this.isGuest = false;
	
	this.startTime = -1;
}

PreCTAssistant.prototype.setup = function() {
	this.utils.setStageController(this.controller.stageController);
	
    this.controller.get("CurrentTime").style.display = "none";
    this.controller.get("StopButton").style.display = "none";
	
    // Setup menu
    this.controller.setupWidget(Mojo.Menu.appMenu, this.attributes = {
        omitDefaultItems: true
    }, this.model = {
        items: [
		{
            label: "Select Puzzle",
            command: "do-selectPuzzle"
        }, {
			label: "Toggle BLD",
            command: "do-toggleBLD"
        }, {
            label: "Toggle OH",
            command: "do-toggleOH"
		}, {
			label: "Toggle Guest Mode",
			command: "do-toggleGuest"
		}, {
			label: "Delete...",
			command: "do-deleteMenu"
		}, {
            label: "About",
            command: "do-myAbout"
        }]
    });
	
	// Setup stop button
    this.controller.setupWidget("StopButton", this.buttonAttributes, this.model = {
        "label": "Stop",
        "buttonClass": "negative",
        "disabled": false
    });
	
    // Add listeners to start and stop buttons
    Event.observe("StopButton", "mousedown", this.stopTiming.bind(this));
	Event.observe("Body","click",this.startTiming.bind(this));
	
	this.puzzleChoose("3x3x3");
	Mojo.Log.info("spdqbr: "+"Setup Finished");
}

PreCTAssistant.prototype.activate = function(event) {}
PreCTAssistant.prototype.deactivate = function(event) {}
PreCTAssistant.prototype.cleanup = function(event) {}

PreCTAssistant.prototype.handleCommand = function(event){
	var methodName = "PreCTAssistant.handleCommand ";
    this.controller = Mojo.Controller.stageController.activeScene();
    
    if (event.type == Mojo.Event.command) {
        switch (event.command) {
            case "do-toggleBLD":
                this.isBLD = !this.isBLD;
                this.puzzleChoose(this.puzzle);
                break;
            case "do-toggleOH":
                this.isOH = !this.isOH;
                this.puzzleChoose(this.puzzle);
                break;
			case "do-toggleGuest":
				this.isGuest = !this.isGuest;
				if (this.isGuest) {
					this.controller.get("TimeLabel").update("Times (Guest)");
				}else{
					this.controller.get("TimeLabel").update("Times");
				}
				this.puzzleChoose(this.puzzle);
				break;
            case "do-selectPuzzle":
                // Pop up a menu for puzzle selection.  
                // "Cube" has its own sub-menu
                this.controller.popupSubmenu({
                    onChoose: this.puzzleChoose,
                    placeNear: event.target,
                    items: [{
                        label: "Cube",
                        command: "selectCube-cmd"
                    }, {
                        label: "Megaminx",
                        command: "Megaminx"
                    }, {
                        label: "Square-1",
                        command: "Square-1"
                    }, {
                        label: "Pyraminx",
                        command: "Pyraminx"
                    }, {
                        label: "UFO",
                        command: "UFO"
                    }]
                })
                break;
			case "do-deleteMenu":
				if (this.isGuest) {
					this.controller.popupSubmenu({
						onChoose: this.doDelete,
						placeNear: event.target,
						items: [{
							label: "Delete last time",
							command: "do-undo"
						}, {
							label: "Delete all times (this puzzle)",
							command: "do-delete"
						}]
					})
				}else{
					this.controller.popupSubmenu({
						onChoose: this.doDelete,
						placeNear: event.target,
						items: [{
							label: "Delete last time",
							command: "do-undo"
						}, {
							label: "Delete all times (this puzzle)",
							command: "do-delete"
						}, {
							label: "Delete all times (all puzzles)",
							command: "do-drop"
						}]
					})					
				}
				break;
            case "do-myAbout":
                Mojo.Controller.stageController.pushScene("Info");
                break;
        }
    }
}

PreCTAssistant.prototype.doDelete = function(command){
    switch (command) {
        case "do-undo":
            this.times.pop();
            if (this.times.length < this.sessionStartIndex) {
                this.sessionStartIndex = this.times.length;
            }
			if (!this.isGuest) {
				this.dbHelper.deleteLastTime(this.puzzle);
			}
            this.displayTimes();
            break;
        case "do-delete":
            this.controller.showAlertDialog({
                onChoose: function(value){
                    if (value == "Yes") {
						if (!this.isGuest) {
							this.dbHelper.deleteTimes(this.puzzle);
						}
                        this.times = [];
                        this.displayTimes();
                    }
                },
                title: $L("Delete?"),
                message: $L("Are you sure you want to delete all times for " + this.puzzle + "?"),
                choices: [{
                    label: $L("Yes"),
                    value: "Yes",
                    type: 'affirmative'
                }, {
                    label: $L("No"),
                    value: "No",
                    type: 'negative'
                }]
            });
            break;
        case "do-drop":
            this.controller.showAlertDialog({
                onChoose: function(value){
                    if (value == "Yes") {
						if (!this.isGuest) {
							this.dbHelper.dropTable();
							this.dbHelper.setupDb();
						}
                        this.times = [];
                        this.sessionStartIndex = 0;
                        this.displayTimes();
                    }
                },
                title: $L("Delete?"),
                message: $L("Are you sure you want to delete ALL times for ALL puzzles?"),
                choices: [{
                    label: $L("Yes"),
                    value: "Yes",
                    type: 'affirmative'
                }, {
                    label: $L("No"),
                    value: "No",
                    type: 'negative'
                }]
            });
            break;
    }
}

PreCTAssistant.prototype.puzzleChoose = function(command){
	var methodName = "PreCTAssistant.puzzleChoose ";
	if(command == null){
		return;
	}
	
	// Keep track of the curent puzzle so we don"t needlessly clear times
    var fs = "20px";
	
	this.puzzle = this.puzzle.replace("-BLD","").replace("-OH","");
	command = command.replace("-BLD","").replace("-OH","")
    
    switch (command) {
        case "selectCube-cmd":
            // Pop up a new selection for the cube size, recursively call this function
            this.controller.popupSubmenu({
                onChoose: this.puzzleChoose,
                placeNear: event.target,
                items: [{
                    label: "2x2x2",
                    command: "2x2x2"
                }, {
                    label: "3x3x3",
                    command: "3x3x3"
                }, {
                    label: "4x4x4",
                    command: "4x4x4"
                }, {
                    label: "5x5x5",
                    command: "5x5x5"
                }, {
                    label: "6x6x6",
                    command: "6x6x6"
                }, {
                    label: "7x7x7",
                    command: "7x7x7"
                }]
            })
            return;
			break;
        case "Megaminx":
            this.puzzle = "Megaminx";
            fs = "13px";
            break;
        case "Square-1":
            this.puzzle = "Square-1";
            break;
        case "Pyraminx":
            this.puzzle = "Pyraminx";
            fs = "24px";
            break;
        case "UFO":
            this.puzzle = "UFO";
            fs = "24px";
            break;
        case "2x2x2":
            this.puzzle = "2x2x2";
            fs = "24px";
            break;
        case "3x3x3":
            this.puzzle = "3x3x3";
            fs = "24px";
            break;
        case "4x4x4":
            this.puzzle = "4x4x4";
            fs = "20px";
            break;
        case "5x5x5":
            this.puzzle = "5x5x5";
            fs = "18px";
            break;
        case "6x6x6":
            this.puzzle = "6x6x6";
            fs = "15px";
            break;
        case "7x7x7":
            this.puzzle = "7x7x7";
            fs = "14px";
            break;
    }
    
    if(this.isBLD){
        this.puzzle = this.puzzle+"-BLD"
    }
    if(this.isOH){
        this.puzzle = this.puzzle+"-OH"
    }
    
    // Set the font appropriate for the puzzle
    this.controller.get("Scramble").style.fontSize = fs;
    
    // Update the scramble header
    this.controller.get("ScrambleType").update("<center>Scramble for " + this.puzzle + "</center>");
	
	Mojo.Log.info("spdqbr: Changing puzzle to "+this.puzzle);
	if (! this.isGuest) {
		this.dbHelper.getTimes(this.puzzle);
	}else{
		this.setTimes([]);
	}
	
	this.scramble();
	this.sessionId = (new Date()).getTime();
}

PreCTAssistant.prototype.scramble = function(){
	this.currentScramble = this.scramblers.scramble(this.puzzle);
	this.controller.get("Scramble").update(this.currentScramble);
}

PreCTAssistant.prototype.startTiming = function(){
	this.startTime = (new Date()).getTime();
	
	this.controller.get("CurrentTime").update("<center>"+this.utils.milsToTime(0)+"</center>");
	
	this.setView(true);
	this.utils.disableScreenBlank();
	
    // Setup the display update schedule to every 100 millis
    this.updateDisplay = this.updateCurrentTime.bind(this);
    this.updateInterval = setInterval(this.updateDisplay, 100);
}

PreCTAssistant.prototype.updateCurrentTime = function(){
	this.controller.get("CurrentTime").update("<center>"+this.utils.milsToTime((new Date())-this.startTime)+"</center>");
}

PreCTAssistant.prototype.stopTiming = function(){
	var time = (new Date()).getTime() - this.startTime;
	clearInterval(this.updateInterval);
	
	this.times.push(time);
	if (!this.isGuest) {
		this.dbHelper.addTime(this.sessionId, this.puzzle, this.currentScramble, time, null);
	}

	this.displayTimes();
	
	this.setView(false);
	
	this.utils.enableScreenBlank();
	this.scramble();
}

PreCTAssistant.prototype.setView = function(isTiming){
	var statStyle = "block";
	var timingStyle = "none";
	if(isTiming){
		statStyle = "none";
		timingStyle = "block";
	}
	
	this.controller.get("CurrentAverage").style.display = statStyle;
	this.controller.get("BestAverage").style.display = statStyle;
	this.controller.get("BestTime").style.display = statStyle;
	this.controller.get("SessionBestAvg").style.display = statStyle;
	this.controller.get("SessionBestTime").style.display = statStyle;
	this.controller.get("SessionSolves").style.display = statStyle;
	this.controller.get("GroupTimes").style.display = statStyle;	
	this.controller.get("ScrambleType").style.display = statStyle;
	this.controller.get("Scramble").style.display = statStyle;
	
	this.controller.get("CurrentTime").style.display = timingStyle;
    this.controller.get("StopButton").style.display = timingStyle;
}

PreCTAssistant.prototype.setTimes = function(times){
	this.times = times;
	this.sessionStartIndex = this.times.length;
	this.displayTimes();
}

PreCTAssistant.prototype.displayTimes = function(){
	if (this.times.length > 0) {
		var bestSolve = Math.min.apply(Math, this.times);
		this.controller.get("BestTime").update("Best Time:<br><center>" + this.utils.milsToTime(bestSolve) + "</center>");
	}
	else {
		this.controller.get("BestTime").update("Best Time:<br><center>--</center>");
	}
	
	var bestAverage = this.utils.calculateBestWeightedAverage(this.times);
	if (bestAverage != null) {
		this.controller.get("BestAverage").update("Best Avg:<br><center>" + this.utils.milsToTime(bestAverage) + "</center>");
	}else{
		this.controller.get("BestAverage").update("Best Avg:<br><center>--</center>");
	}

	var sessionTimes = this.times.slice(this.sessionStartIndex,this.times.length);
	
	if (sessionTimes.length > 0) {
		var sessionBestSolve = Math.min.apply(Math, sessionTimes);
		this.controller.get("SessionBestTime").update("<center>Session</center><center>Best Time:</center><center>" + this.utils.milsToTime(sessionBestSolve) + "</center>");
	}else{
		this.controller.get("SessionBestTime").update("<center>Session</center><center>Best Time:</center><center>--</center>");
	}
	
	var sessionBestAverage = this.utils.calculateBestWeightedAverage(sessionTimes);
	if (sessionBestAverage != null) {
		this.controller.get("SessionBestAvg").update("<center>Session</center><center>Best Avg:</center><center>" + this.utils.milsToTime(sessionBestAverage) + "</center>");
	}else{
		this.controller.get("SessionBestAvg").update("<center>Session</center><center>Best Avg:</center><center>--</center>");
	}
	
	var rollingSet = this.times.slice(Math.max(0,this.times.length-12),this.times.length);
	var bestRollingSolve = Math.min.apply(Math, rollingSet);
	var worstRollingSolve = Math.max.apply(Math, rollingSet);

	var rollingAverage = this.utils.calculateWeightedAverage(rollingSet);
	if (rollingAverage != null) {
		this.controller.get("CurrentAverage").update("Current Avg:<br><center>" + this.utils.milsToTime(rollingAverage) + "</center>");
	}else{
		this.controller.get("CurrentAverage").update("Current Avg:<br><center>--</center>");
	}
	
	var startIndex = Math.max(0,this.times.length-12);
	for(var i = 0; i < 12; i++){
		var element = this.controller.get("Time"+(startIndex+i)%12);
		element.style.color = "black";
		if ((i+startIndex) >= this.times.length) {
			element.update((i + 1) + ")   --");
		}
		else {
			element.update((startIndex+i)%12+1+") "+this.utils.milsToTime(this.times[i+startIndex]));
			if(this.times[i+startIndex] == bestRollingSolve){
				element.style.color = "green";
			}
			if(this.times[i+startIndex] == worstRollingSolve){
				element.style.color = "red";
			}
		}
	}
	this.controller.get("Time"+this.times.length%12).style.color = "blue";
	
	this.controller.get("SessionSolves").update("<center>Session</center><center>Solves:</center><center>"+(this.times.length-this.sessionStartIndex)+"</center>");
}